/**
 * LiteAvatar WebSocket 客户端
 * 用于连接到 service.py 数字人服务
 * 
 * 支持两种模式：
 * - 图片帧模式：ws://localhost:8765 (service_img.py)
 * - 视频流模式：ws://localhost:8766 (service_video.py)
 */
export class LiteAvatarClient {
  constructor(mode = 'image') {
    this.ws = null
    this.isConnected = false
    this.frameCallback = null
    this.videoCallback = null  // 🎬 用于接收语音视频片段（视频流模式）
    this.idleCallback = null   // 😴 用于接收待机视频（视频流模式）
    this.statusCallback = null
    this.errorCallback = null
    this.mode = mode  // 'image' 或 'video'
    
    // 🔑 统一使用同一个端口，模式由初始化时指定
    this.defaultPort = 8765
  }

  /**
   * 连接到 WebSocket 服务（统一端口，模式通过初始化时指定）
   * @param {string} wsUrl - WebSocket服务地址（可选，默认 ws://localhost:8765）
   */
  async connect(wsUrl = null) {
    // 如果没有提供 wsUrl，使用默认端口
    if (!wsUrl) {
      wsUrl = `ws://localhost:${this.defaultPort}`
    }
    
    const modeEmoji = this.mode === 'image' ? '🖼️' : '🎬'
    const modeName = this.mode === 'image' ? 'IMAGE FRAME' : 'VIDEO STREAM'
    console.log(`${modeEmoji} Connecting to LiteAvatar service (${modeName} mode): ${wsUrl}`)
    return new Promise((resolve, reject) => {
      try {
        this.ws = new WebSocket(wsUrl)
        
        // 🚀 关键修复：设置 WebSocket 以 Blob 格式接收二进制数据
        this.ws.binaryType = 'blob'
        
        this.ws.onopen = () => {
          console.log('✅ LiteAvatar WebSocket connected')
          this.isConnected = true
          this.statusCallback?.('connected')
          resolve()
        }
        
        this.ws.onmessage = (event) => {
          try {
            // 🚀 二进制传输优化：区分二进制帧数据和文本控制消息
            if (event.data instanceof Blob) {
              // 接收到二进制视频帧数据
              console.log(`🎬 Received binary frame (${event.data.size} bytes)`)
              this.frameCallback?.(event.data)  // 直接传递 Blob
            } else if (event.data instanceof ArrayBuffer) {
              // 接收到 ArrayBuffer 格式的视频帧
              const blob = new Blob([event.data], { type: 'image/webp' })
              console.log(`🎬 Received binary frame (${blob.size} bytes)`)
              this.frameCallback?.(blob)
            } else {
              // 接收到文本消息（JSON 控制消息）
              const data = JSON.parse(event.data)
              
              if (data.type === 'init_ack') {
                console.log('✅ Avatar initialized:', data.avatar_id, data.status)
                this.statusCallback?.('initialized')
              } else if (data.type === 'idle_video') {
                // 😴 接收到待机视频
                console.log(`😴 Received idle video: ${data.duration}s, format: ${data.format || 'video/webm'}`)
                // 解码Base64视频数据
                const videoData = atob(data.data)
                const videoArray = new Uint8Array(videoData.length)
                for (let i = 0; i < videoData.length; i++) {
                  videoArray[i] = videoData.charCodeAt(i)
                }
                const videoFormat = data.format || 'video/webm'
                const videoBlob = new Blob([videoArray], { type: videoFormat })
                this.idleCallback?.(videoBlob)
              } else if (data.type === 'video_segment') {
                // 🎬 接收到语音视频片段（完整语句的视频）
                console.log(`🎬 Received speech video segment: ${data.duration}s, ${data.frames} frames, format: ${data.format || 'video/mp4'}`)
                // 解码Base64视频数据
                const videoData = atob(data.data)
                const videoArray = new Uint8Array(videoData.length)
                for (let i = 0; i < videoData.length; i++) {
                  videoArray[i] = videoData.charCodeAt(i)
                }
                // 使用后端指定的视频格式
                const videoFormat = data.format || 'video/mp4'
                const videoBlob = new Blob([videoArray], { type: videoFormat })
                this.videoCallback?.(videoBlob, data.duration, data.frames)
              } else if (data.type === 'reset_ack') {
                console.log('✅ Buffer reset')
              } else if (data.type === 'flush_ack') {
                console.log('✅ Buffer flushed')
              } else if (data.error) {
                console.error('❌ Server error:', data.error)
                this.errorCallback?.(data.error)
              }
            }
          } catch (error) {
            console.error('❌ Failed to parse message:', error)
          }
        }
        
        this.ws.onerror = (error) => {
          console.error('❌ WebSocket error:', error)
          this.statusCallback?.('error')
          this.errorCallback?.(error)
          reject(error)
        }
        
        this.ws.onclose = () => {
          console.log('🔌 WebSocket disconnected')
          this.isConnected = false
          this.statusCallback?.('disconnected')
        }
      } catch (error) {
        console.error('❌ Failed to create WebSocket:', error)
        reject(error)
      }
    })
  }

  /**
   * 初始化 avatar
   * @param {string} avatarId - Avatar ID
   */
  async initAvatar(avatarId = 'P1d5LAiX3CqPUMXODP75gxiQ') {
    if (!this.isConnected) {
      throw new Error('WebSocket not connected')
    }
    
    const modeEmoji = this.mode === 'image' ? '🖼️' : '🎬'
    const modeName = this.mode === 'image' ? 'IMAGE FRAME' : 'VIDEO STREAM'
    console.log(`${modeEmoji} Initializing avatar (${modeName} mode):`, avatarId)
    
    const message = {
      type: 'init',
      avatar_id: avatarId,
      mode: this.mode  // 🔑 发送模式信息给服务端
    }
    
    this.ws.send(JSON.stringify(message))
  }

  /**
   * 发送音频数据
   * - 图片帧模式(image): 发送 pcm_audio，用于逐帧生成
   * - 视频流模式(video): 发送 speech_segment，用于完整句子生成
   * @param {ArrayBuffer} pcmData - PCM 音频数据
   */
  sendAudio(pcmData) {
    // 检查连接状态：必须是已连接且 WebSocket 处于 OPEN 状态
    if (!this.isConnected || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
      // 静默返回，避免在清理阶段产生大量警告
      return
    }
    
    // 将ArrayBuffer转换为Base64
    const uint8Array = new Uint8Array(pcmData)
    let binary = ''
    for (let i = 0; i < uint8Array.length; i++) {
      binary += String.fromCharCode(uint8Array[i])
    }
    const base64Data = btoa(binary)
    
    // 🔑 根据模式发送不同类型的消息
    let message
    if (this.mode === 'image') {
      // 图片帧模式：发送 pcm_audio（逐帧生成）
      message = {
        type: 'pcm_audio',
        data: base64Data
      }
      // 减少日志输出（图片帧模式发送频率高）
      if (Math.random() < 0.05) { // 5% 概率打印
        console.log(`🖼️ [IMG] Sending PCM audio: ${pcmData.byteLength} bytes`)
      }
    } else {
      // 视频流模式：发送 speech_segment（完整语句）
      message = {
        type: 'speech_segment',
        data: base64Data
      }
      console.log(`🎬 [VIDEO] Sending complete sentence: ${pcmData.byteLength} bytes`)
    }
    
    this.ws.send(JSON.stringify(message))
  }

  /**
   * 注册帧回调函数
   * @param {Function} callback - 回调函数，接收 base64 图像数据
   */
  onFrame(callback) {
    this.frameCallback = callback
  }

  /**
   * 注册语音视频片段回调函数
   * @param {Function} callback - 回调函数，接收 video Blob, duration, frames
   */
  onVideo(callback) {
    this.videoCallback = callback
  }

  /**
   * 注册待机视频回调函数
   * @param {Function} callback - 回调函数，接收 idle video Blob
   */
  onIdle(callback) {
    this.idleCallback = callback
  }

  /**
   * 注册状态回调函数
   * @param {Function} callback - 回调函数，接收状态字符串
   */
  onStatus(callback) {
    this.statusCallback = callback
  }

  /**
   * 注册错误回调函数
   * @param {Function} callback - 回调函数，接收错误信息
   */
  onError(callback) {
    this.errorCallback = callback
  }

  /**
   * 重置缓冲区
   */
  reset() {
    if (!this.isConnected) {
      console.warn('⚠️ Cannot reset: not connected')
      return
    }
    
    console.log('🔄 Resetting buffer...')
    this.ws.send(JSON.stringify({
      type: 'control',
      command: 'reset'
    }))
  }

  /**
   * 刷新缓冲区中剩余的所有数据
   */
  flush() {
    if (!this.isConnected) {
      console.warn('⚠️ Cannot flush: not connected')
      return
    }
    
    console.log('💧 Flushing buffer...')
    this.ws.send(JSON.stringify({
      type: 'control',
      command: 'flush'
    }))
  }

  /**
   * 断开连接
   */
  disconnect() {
    if (this.ws) {
      console.log('👋 Disconnecting WebSocket...')
      this.ws.close()
      this.ws = null
      this.isConnected = false
    }
  }
}

